/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package prueba;

/**
 *
 * @author tlamatron
 */
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

import java.util.Random;

 class Monitor {

 private final int DER = 1;
 private final int IZQ = 0;
 private final int NONE = -1;
 private final int MAX_SEGUIDOS = 3;
 private final int CAPACIDAD_PUENTE = 5;
 private int cola_coches_izq;
 private int cola_coches_der;
 private int coches_puente_izq;
 private int coches_puente_der;
 int turno;
 int seguidos;
 int ocupacion;
 Monitor mon_izq;
 Monitor mon_der;
 
 public Monitor() {
 cola_coches_der = cola_coches_izq = 0;
 coches_puente_der = coches_puente_izq = 0;
 turno = NONE;
 seguidos = 0;
ocupacion = 0;
 }

 public Monitor(Monitor izq, Monitor der) {
 this();
 this.mon_der = izq;
 this.mon_izq = der;
 }

 public synchronized void llega_coche_izq(int id) {
 print("El coche " + id + " llega a la cola (izq)");
 cola_coches_izq++;
 }

 public synchronized void llega_coche_der(int id) {
 print("El coche " + id + " llega a la cola (der)");
 cola_coches_der++;
 }

 public synchronized void sale_coche_izq(int id) {
 print("El coche " + id + " sale del puente (izq)");
 boolean ultimo = false;
 coches_puente_izq--;
 ocupacion--;
 if (ocupacion == 0) {
 ultimo = true;
 }
 if (coches_puente_izq == 0) {
 if (coches_puente_der > 0) {
 turno = DER;
 } else {
 turno = NONE;
 }
 if (seguidos == MAX_SEGUIDOS) {
 seguidos = 0;
 }
 }
 if ((turno == IZQ || turno == NONE) && seguidos <
MAX_SEGUIDOS && !ultimo && ocupacion < CAPACIDAD_PUENTE)
{
 despertar_izq();
 } else if (ultimo && turno == DER) {
 despertar_der();
 }
 }
 
 
 public synchronized void sale_coche_der(int id) {
 print("El coche " + id + " sale del puente (der)");
 boolean ultimo = false;
 coches_puente_der--;
 ocupacion--;
 if (ocupacion == 0) {
 ultimo = true;
 }
 if (coches_puente_der == 0) {
 if (coches_puente_izq > 0) {
    
turno = IZQ;
 } else {
 turno = NONE;
 }
 if (seguidos == MAX_SEGUIDOS) {
 seguidos = 0;
 }
 }
 if ((turno == DER || turno == NONE) && seguidos <
MAX_SEGUIDOS && !ultimo && ocupacion < CAPACIDAD_PUENTE)
{
 despertar_der();
 } else if (ultimo && turno == IZQ) {
 despertar_izq();
 }
 }
 
 
 

 private void despertar_izq() {
 try {
 this.mon_izq.notify();
 } catch (Exception e) {
 }
 }

 private void despertar_der() {
 try {
 this.mon_der.notify();
 } catch (Exception e) {
 }
 }


public synchronized void pasa_coche_izq(int id) {
 try {
 if (turno == DER || seguidos >= MAX_SEGUIDOS ||
 ocupacion >= CAPACIDAD_PUENTE) {
 mon_izq.wait();
 }
 turno = IZQ;
 print("El coche " + id + " esta cruzando el puente (izq)");
 coches_puente_izq++;
 ocupacion++;
 print("Ocupacion del puente: " + ocupacion + "/" + CAPACIDAD_PUENTE);
 cola_coches_izq--; //Lo quitamos de la cola
 if (cola_coches_der > 0) {
 seguidos++;
 }
 print("Coches seguidos mientras en DER esperan: " + seguidos + "/" + MAX_SEGUIDOS);
 } catch (InterruptedException ex) {
 print("ERROR al dormir al coche " + id);
 }
 }

 public synchronized void pasa_coche_der(int id) {
try {
 if (turno == IZQ || seguidos >= MAX_SEGUIDOS ||
 ocupacion >= CAPACIDAD_PUENTE) {
 mon_der.wait();
 }
 turno = DER;
 print("El coche " + id + " esta cruzando el puente (der)");
 coches_puente_der++;
 ocupacion++;
 print("Ocupacion del puente: " + ocupacion + "/" + CAPACIDAD_PUENTE);
 cola_coches_der--; //Lo quitamos de la cola
 if (cola_coches_izq > 0) {
 seguidos++;
 }
 print("Coches seguidos mientras en IZQ esperan: " + seguidos + "/" + MAX_SEGUIDOS);
 } catch (InterruptedException ex) {
 print("ERROR al dormir al coche " + id);
 }

}

 private void print(String s) {
 System.out.println(s);
 }
 }


class Coche extends Thread {

 private final int IZQ = 0;
 private final int DER = 1;
 private int sentido;
 private static int n = 0;
 Monitor monitor;
 private int id;

 public Coche(Monitor monitor) {
 n++;
 id = n;
 this.monitor = monitor;
 }
	@Override
	public void run() {
 try {
 //Esperamos un tiempo aleatorio
 sleep((long) ((new Random()).nextInt(10000)));
 this.sentido = (new Random()).nextInt(2); //genera un entero 0 o 1
 if (sentido == IZQ) {
 alPuentePorLaIzquierda();
 } else if (sentido == DER) {
 alPuentePorLaDerecha();
 } else {
System.out.println("ERROR: En el coche " + id + "se ha generado un sentido no valido.");
 }
 } catch (InterruptedException ex) {
 }
 }

 private void alPuentePorLaIzquierda() {
 try {
 monitor.llega_coche_izq(id);
 monitor.pasa_coche_izq(id);
 sleep(1000);
 monitor.sale_coche_izq(id);
 } catch (Exception e) {
 }
 }

 private void alPuentePorLaDerecha() {
 try {
 monitor.llega_coche_der(id);
 monitor.pasa_coche_der(id);
 sleep(1000);
 monitor.sale_coche_der(id);
 } catch (Exception e) {
 }
 }
 }

public class PuenteDueroMonitores {

 static int ncoches = 10;

 public static void main(String[] args) {
 Monitor aux_izq = new Monitor();
 Monitor aux_der = new Monitor();
 Monitor puente = new Monitor(aux_izq, aux_der);
 Coche aux;
 for (int i = 0; i < ncoches; i++) {
 aux = new Coche(puente);
 aux.start();
 }
 }
 }
